using CfgTable;
using Cysharp.Threading.Tasks;
using IQIGame.Onigao.Framework;
using IQIGame.Onigao.Game;
using IQIGame.Onigao.GameAOT;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;

namespace IQIGame.Onigao.GamePlay
{
    public class UIN_MiniMap : UIBaseNode, IMapContainer
    {
        #region Template Generate,don't modify

        protected class UIB_UIN_MiniMap
        {
            #region ObjectBinding Generate

            public ExButton miniMap { protected set; get; }
            public RectTransform container { protected set; get; }
            public ExImage alert { protected set; get; }
            public ExText mapName { protected set; get; }
            public virtual void InitBinding(ObjectBinding __binding)
            {
                __binding.TryGetVariableValue<ExButton>("miniMap", out var __tbv0);
                miniMap = __tbv0;
                __binding.TryGetVariableValue<RectTransform>("container", out var __tbv1);
                container = __tbv1;
                __binding.TryGetVariableValue<ExImage>("alert", out var __tbv2);
                alert = __tbv2;
                __binding.TryGetVariableValue<ExText>("mapName", out var __tbv3);
                mapName = __tbv3;
            }


            #endregion ObjectBinding Generate
        }

        #endregion Template Generate,don't modify

        #region properties

        protected UIB_UIN_MiniMap ui { get; set; }
        protected UIMsgDispatcher uiMsgDispatcher => _msgDispatcher as UIMsgDispatcher;

        #endregion properties

        #region Override

        protected override void BeforeInit()
        {
            ui = new UIB_UIN_MiniMap();
            ui.InitBinding(csObjBind);
        }

        protected override void OnInit()
        {
            ui.miniMap.AddClickEvent(OnMapClick);
        }

        protected override void OnShow()
        {
            BindMap(GameplayAreaManager.Instance.curSceneArea.curRegionCid).Forget();
        }

        protected override void OnHide()
        {

        }

        protected override void AddMsgListeners()
        {
            uiMsgDispatcher.AddListener<int, int, int>(MsgEventType.Level_UpdateEntityAlert, OnEntityAlertUpdate);
            uiMsgDispatcher.AddListener<int>(MsgEventType.Level_EntityStartHide, OnEntityDestroy);
            uiMsgDispatcher.AddListener(MsgEventType.StartSwitchGameplayArea, OnStartSwitchGameplayArea);
            uiMsgDispatcher.AddListener(MsgEventType.GameplayAreaSceneLoaded, OnGameplayAreaSceneLoaded);
        }

        private void OnGameplayAreaSceneLoaded()
        {
            BindMap(GameplayAreaManager.Instance.curSceneArea.curRegionCid).Forget();
        }

        private void OnStartSwitchGameplayArea()
        {
            _mapRoot?.DetachFrom(this);
        }

        protected override void OnUpdate(float dt, float unscaledDt)
        {
            if (_mapRoot == null)
            {
                return;
            }
            var curArea = GameplayAreaManager.Instance.curSceneArea;
            if (!curArea.isSceneReady)
            {
                return;
            }

            UpdateScaleForMoving(dt);
            _mapRoot.FocusPlayer(true);
            if ((_passedTime += dt) < UpdateInterval)
            {
                return;
            }

            _passedTime = 0f;
            UpdateMiniMapEntities();
            CheckTracingEntityNearby();
        }

        protected override void OnDispose()
        {
            _mapRoot?.DetachFrom(this);
        }

        #endregion

        #region methonds

        private async UniTaskVoid BindMap(int regionCid)
        {
            var map = await UIMapManager.Instance.LoadMap(regionCid);
            if (map == null || map.transform == null)
            {
                Debug.LogError($"Can not load map regionCid:{regionCid}");
                return;
            }

            map.AttachTo(this);
            map.CreatePlayer();
            map.CreateFog();
            ui.mapName.text = TableCenter.regionInstance.Get(regionCid)?.Name ?? string.Empty;
        }

        private void OnMapClick()
        {
            UILevelMap.Open(_mapRoot.regionCid, 0).Forget();
        }

        private void UpdateMiniMapEntities()
        {
            if (_mapRoot == null)
                return;
            _deleteEntities.AddRange(_activeEntities);
            var entities = ListPool<TViewEntity>.Get();
            GameScenePlayUtil.GetSmallMapEntities(entities);
            var targets = ListPool<TViewEntity>.Get();
            //任务实体
            GameScenePlayUtil.GetQuestTrackEntities(targets, out var regionCid);
            if (regionCid == _mapRoot.regionCid)
            {
                entities.AddRange(targets);
            }

            ListPool<TViewEntity>.Put(targets);
            //追踪实体
            var tracingEntity = GameplayAreaManager.Instance.curSceneArea?.GetTrackingEntity();
            if (tracingEntity != null)
            {
                entities.Add(tracingEntity);
            }

            foreach (var entity in entities)
            {
                var entityId = entity.id;
                var mapUIEntityCid = entity.mapSymbolCid;
                if (entityId == 0 || mapUIEntityCid == 0 ||
                    TableCenter.mapUiEntity.Get(mapUIEntityCid).Type == MapUiEntityType.Fog)
                {
                    continue;
                }

                _deleteEntities.Remove(entityId);

                if (!_activeEntities.TryAdd(entityId, TableCenter.mapUiEntity.Get(mapUIEntityCid).Type))
                {
                    continue;
                }

                _mapRoot.AddSymbol(entity);
            }

            foreach (var kvp in _deleteEntities)
            {
                _activeEntities.Remove(kvp.Key);
                _mapRoot.RemoveAllSymbolByEntityId(kvp.Key);
            }

            _deleteEntities.Clear();
            ListPool<TViewEntity>.Put(entities);
        }

        private void InitScale()
        {
            var containerSize = containerRT.sizeDelta;
            //视口大小/比例尺/2 = 视口可视半径
            //scale = 视口可视半径/实体搜索半径
            _initialScale = Mathf.Max(containerSize.x, containerSize.y) / Mathf.Abs(_mapRoot.factor) / 2 / 10;
            //移动时的可视范围
            _minScale = Mathf.Max(containerSize.x, containerSize.y) / Mathf.Abs(_mapRoot.factor) / 2 / 15;
            _mapRoot.SetScale(_initialScale);
        }

        private void UpdateScaleForMoving(float dt)
        {
            if (GameScenePlayUtil.IsPlayerMoving())
            {
                _movingTime += dt;
            }
            else
            {
                _movingTime -= dt;
            }

            switch (_movingTime)
            {
                case < 0:
                    _movingTime = 0;
                    return;
                case > 1:
                    _movingTime = 1;
                    return;
                default:
                    {
                        var movingScale = Mathf.Lerp(_initialScale, _minScale, _movingTime);
                        _mapRoot.SetScale(movingScale);
                        break;
                    }
            }
        }

        private void OnEntityAlertUpdate(int entityId, int targetEntityId, int alertValue)
        {
            SetAlert(entityId, alertValue);
        }

        private void OnEntityDestroy(int entityId)
        {
            _mapRoot?.GetLayer((int)StaticLayerType.FogLayer)?.RemoveSymbol(entityId);
            SetAlert(entityId, 0);
        }

        private void SetAlert(int entityId, int alert)
        {
            if (entityId == 0)
            {
                return;
            }

            if (alert == 0)
            {
                if (!_alerts.Remove(entityId))
                {
                    return;
                }
            }
            else
            {
                _alerts[entityId] = alert;
            }

            var max = _alerts.Count > 0 ? _alerts.Values.Max() : 0;
            if (max == 0)
            {
                ui.alert.SetActive(false);
                return;
            }

            ui.alert.SetActive(true);
            ui.alert.color = max is > 0 and < 100 ? Color.yellow : Color.red;
        }

        private void CheckTracingEntityNearby()
        {
            if (GameplayAreaManager.Instance.curArea is not IGameplaySceneArea curArea)
            {
                return;
            }

            var target = curArea.GetTrackingEntity();
            if (target == null)
            {
                return;
            }

            var playerWorldPos = curArea.GetPlayerAvatarEntity().transform.position;
            if (Vector3.Distance(playerWorldPos, target.transform.position) <= LevelDataConsts.QuadTreeSearchHalfSize)
            {
                CancelTracing().Forget();
            }
        }

        private async UniTaskVoid CancelTracing()
        {
            if (GameplayAreaManager.Instance.curArea is not IGameplaySceneArea curArea || _waitingCancelTracing)
            {
                return;
            }

            NoticeModule.ShowNoticeNoCall(500014);
            _waitingCancelTracing = true;
            await curArea.MarkTrackingEntity(0);
            _waitingCancelTracing = false;
            _mapRoot.ChangeTraceEntity();
        }

        #endregion methonds

        #region fields

        private UIMapRoot _mapRoot;

        private readonly Dictionary<int, MapUiEntityType> _activeEntities = new();

        private readonly Dictionary<int, MapUiEntityType> _deleteEntities = new();

        private const float UpdateInterval = 1f;

        private float _passedTime;

        private float _initialScale;

        private float _minScale;

        private float _movingTime;

        private readonly Dictionary<int, int> _alerts = new();

        private bool _waitingCancelTracing;

        #endregion

        #region IMapContainer Implement

        public bool interactable => false;
        public RectTransform containerRT => ui.container;

        public void OnMapAttach(UIMapRoot root)
        {
            _mapRoot = root;
            isUpdate = true;
            _mapRoot.updatable = true;
            InitScale();
            _mapRoot.FocusPlayer(true);
            UpdateMiniMapEntities();
            _mapRoot.RefreshAllTracer();
        }

        public void OnMapDetach()
        {
            isUpdate = false;
            _mapRoot.updatable = false;
            _mapRoot.SetScale(1);
            _activeEntities.Clear();
            _deleteEntities.Clear();
            _mapRoot.ClearSymbols();
            _mapRoot = null;
        }

        public bool FilterMapSymbol(IMapSymbolData data)
        {
            return data.config.MapDisplay is MapDisplayType.All or MapDisplayType.OnlyMiniMap;
        }

        public void HandleSymbolInteract(IMapSymbolData data)
        {
            UILevelMap.Open(_mapRoot.regionCid, 0).Forget();
        }

        public float radius => containerRT.sizeDelta.x * 0.5f;

        #endregion
    }
}